﻿using System.Buffers;
using System.Collections.Concurrent;
using System.Net.WebSockets;
using System.Text;

namespace MicrosoftWebSocket6._0Server
{
    internal class Program
    {
        static void Main(string[] args)
        {
            var server = new WebSockSvr();
            server.Start();

            server.SendDatas();
            Console.ReadLine();
        }
    }

    public class WebSockSvr
    {
        public ConcurrentDictionary<string, WebSocket> ClinetList { get; set; } = new();
        WebApplication server;
        public WebSockSvr()
        {
            var builder = WebApplication.CreateBuilder();
            builder.WebHost.UseKestrel(opts =>
            {
                opts.ListenAnyIP(4040);
            });
            server = builder.Build();
            server.UseWebSockets(new WebSocketOptions
            {
                KeepAliveInterval = TimeSpan.FromSeconds(60),
            });
            server.Use(async (context, next) =>
            {
                if (!context.WebSockets.IsWebSocketRequest)
                {
                    await next.Invoke(context);
                    return;
                }
                var id = Guid.NewGuid().ToString("N");
                try
                {
                    var socket = await context.WebSockets.AcceptWebSocketAsync();

                    var buffer = ArrayPool<byte>.Shared.Rent(1024);
                    ClinetList.TryAdd(id, socket);
                    while (socket.State == WebSocketState.Open)
                    {
                        var result = await socket.ReceiveAsync(buffer, CancellationToken.None);
                        if (result.MessageType == WebSocketMessageType.Close)
                        {
                            throw new WebSocketException(WebSocketError.ConnectionClosedPrematurely, result.CloseStatusDescription);
                        }
                        var text = Encoding.UTF8.GetString(buffer.AsSpan(0, result.Count));
                        var sendStr = Encoding.UTF8.GetBytes($"Echo: {text}");
                        await socket.SendAsync(sendStr, WebSocketMessageType.Text, true, CancellationToken.None);
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"WebSocket has exception, {ex.Message}\r\n{ex.StackTrace}");
                }
                finally
                {
                    ClinetList.Remove(id, out _);
                }
            });
        }

        public void Start()
        {
            server.Start();
        }

        public void SendDatas()
        {
            for (int i = 0; i < 200; i++)
            {
                Task.Run(async () =>
                {
                    while (true)
                    {
                        try
                        {
                            foreach (var (id, sock) in ClinetList)
                            {
                                if (sock.State == WebSocketState.Open)
                                {
                                    var sendStr = Encoding.UTF8.GetBytes($"Dev[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}, 12.34, 34.56, 56.78, \"77705683\"]");
                                    await sock.SendAsync(sendStr, WebSocketMessageType.Text, true, CancellationToken.None);
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine($"SendDatas has exception,{ex.Message}\r\n{ex.StackTrace}");
                        }
                        finally
                        {
                            await Task.Delay(10);
                        }
                    }
                });
            }
        }
    }
}
